package com.laomo.lib_bt;

import android.annotation.SuppressLint;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothGatt;
import android.bluetooth.BluetoothGattCallback;
import android.bluetooth.BluetoothGattCharacteristic;
import android.bluetooth.BluetoothGattDescriptor;
import android.bluetooth.BluetoothGattService;
import android.bluetooth.BluetoothManager;
import android.bluetooth.le.BluetoothLeScanner;
import android.bluetooth.le.ScanCallback;
import android.bluetooth.le.ScanFilter;
import android.bluetooth.le.ScanResult;
import android.bluetooth.le.ScanSettings;
import android.content.Context;
import android.os.Handler;
import android.os.ParcelUuid;
import android.text.TextUtils;
import android.util.Log;

import com.jieli.jl_bt_ota.constant.BluetoothConstant;
import com.laomo.lib_bt.callback.CharacteristicCallbackInterface;
import com.laomo.lib_bt.callback.ConnectCallbackInterface;
import com.laomo.lib_bt.callback.ScanCallbackInterface;
import com.laomo.lib_bt.ota.OTAManager;
import com.laomo.lib_bt.util.WriteUtil;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;

/**
 * 类说明：
 *
 * @author laomo
 * @date 2024/8/13 13:40
 */
public class BleManager {
    public static final String TAG = "BleManager";
    private BluetoothManager mBluetoothManager;
    private final Context mContext;
    private BluetoothLeScanner mBluetoothLeScanner;
    private BluetoothAdapter mBluetoothAdapter;
    private Handler mHandler = new Handler();
    private static BleManager mInstance;

    //数据通讯uuid信息
    private String uuid_server = "";
    private String uuid_write_1 = "";
    private String uuid_write_2 = "";
    private String uuid_notify = "";

    //ota相关的uuid信息
    private String uuid_server_ota = "";
    private String uuid_write_ota = "";
    private String uuid_notify_ota = "";

    //扫描结果
    private Map<String, ScanResult> mScanResultMap = new HashMap<>();

    //扫描结果监听
    private List<ScanCallbackInterface> mScanCallbackList = new ArrayList<>();

    //数据监听
    private List<CharacteristicCallbackInterface> mCharacteristicCallbackList = new ArrayList<>();

    //连接事件分发器
    private ConnectEventUtil mConnectEventUtil = new ConnectEventUtil();

    //已经连接的设备
    private LinkedHashMap<String, BluetoothGatt> mGattMap = new LinkedHashMap<>();

    //等待开启通知的characteristic
    private List<BluetoothGattCharacteristic> mReadCharacteristicList = new ArrayList<>();


    public void addCharacteristicCallbackListener(CharacteristicCallbackInterface characteristicCallbackInterface) {
        if (!mCharacteristicCallbackList.contains(characteristicCallbackInterface)) {
            mCharacteristicCallbackList.add(characteristicCallbackInterface);
        }
    }

    public void removeCharacteristicCallbackListener(CharacteristicCallbackInterface characteristicCallbackInterface) {
        mCharacteristicCallbackList.remove(characteristicCallbackInterface);
    }

    public void addConnectCallbackListener(ConnectCallbackInterface connectCallbackInterface) {
        mConnectEventUtil.addConnectCallbackListener(connectCallbackInterface);
    }

    public void removeConnectCallbackListener(ConnectCallbackInterface connectCallbackInterface) {
        mConnectEventUtil.removeConnectCallbackListener(connectCallbackInterface);
    }

    public void addScanCallbackListener(ScanCallbackInterface scanCallbackInterface) {
        if (!mScanCallbackList.contains(scanCallbackInterface)) {
            mScanCallbackList.add(scanCallbackInterface);
        }
    }

    public void removeScanCallbackListener(ScanCallbackInterface scanCallbackInterface) {
        mScanCallbackList.remove(scanCallbackInterface);
    }


    public static BleManager getInstance(Context context) {
        if (mInstance == null) { // 第一次检查，提高性能
            synchronized (BleManager.class) {
                if (mInstance == null) { // 第二次检查，确保线程安全
                    mInstance = new BleManager(context);
                }
            }
        }
        return mInstance;
    }

    private BleManager(Context context) {
        mContext = context;
        mBluetoothManager = (BluetoothManager) context.getApplicationContext().getSystemService(Context.BLUETOOTH_SERVICE);
        mBluetoothAdapter = mBluetoothManager.getAdapter();
        if (mBluetoothAdapter != null) {
            if (mBluetoothAdapter.isEnabled()) {
                // 蓝牙已打开

            } else {
                // 蓝牙未打开

            }
        }
    }


    private ScanCallback mScanCallback = new ScanCallback() {
        @Override
        public void onScanResult(int callbackType, ScanResult result) {
            super.onScanResult(callbackType, result);
            if (result != null && result.getDevice() != null) {
                BluetoothDevice device = result.getDevice();
                String deviceAddress = device.getAddress();
                String name = device.getName();

                byte[] bytes = result.getScanRecord().getBytes();
                if (bytes == null || bytes.length < 20) {
                    return;
                }
                if (!TextUtils.isEmpty(deviceAddress) && !TextUtils.isEmpty(name)) {

                    mScanResultMap.put(deviceAddress, result);
                    // 扫描到BLE设备
                    //Log.d(TAG, "BLE device found: " + device.getName() + "   " + deviceAddress);

                    for (ScanCallbackInterface scanCallbackInterface : mScanCallbackList) {
                        scanCallbackInterface.onScanResult(callbackType, result);
                    }
                }
            }
        }
    };


    //扫描超时
    private Runnable mScanTimeOut = () -> stopScan();

    /**
     * 开始扫描
     *
     * @param timeout 超时时间,毫秒
     */
    @SuppressLint("MissingPermission")
    public void startScan(long timeout) {
        if (mBluetoothLeScanner == null) {
            mBluetoothLeScanner = mBluetoothAdapter.getBluetoothLeScanner();
        }
        mHandler.removeCallbacks(mScanTimeOut);
        mScanResultMap.clear();
        for (ScanCallbackInterface scanCallbackInterface : mScanCallbackList) {
            scanCallbackInterface.onStartScan();
        }

        ScanSettings settings = new ScanSettings.Builder()
                .setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY)
                //.setReportDelay(5000) // 延迟 5 秒后报告批量结果
                .build();

        mBluetoothLeScanner.startScan(null, settings, mScanCallback);
        if (timeout > 0) {
            mHandler.postDelayed(mScanTimeOut, timeout);
        }
    }

    private boolean startReadCharacteristic(BluetoothGatt gatt) {
        boolean flag = false;
        if (!mReadCharacteristicList.isEmpty()) {
            BluetoothGattCharacteristic remove = mReadCharacteristicList.remove(0);
            if (remove != null) {
                flag = true;
                gatt.setCharacteristicNotification(remove, true);
                List<BluetoothGattDescriptor> descriptors = remove.getDescriptors();
                for (BluetoothGattDescriptor descriptor : descriptors) {
                    Log.d(TAG, "onConnectionStateChange: " + descriptor.getUuid());
                    descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
                    gatt.writeDescriptor(descriptor);
                }
            }
        }
        return flag;
    }

    /**
     * 连接设备
     *
     * @param address
     */
    public void connect(String address) {
        //根据地址获取设备
        connect(mBluetoothAdapter.getRemoteDevice(address));
    }

    public void connect(BluetoothDevice device) {
        String address = device.getAddress();
        mConnectEventUtil.onConnecting(address, device);
        //连接设备
        device.connectGatt(mContext, false, new BluetoothGattCallback() {
            @Override
            public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
                super.onConnectionStateChange(gatt, status, newState);
                if (newState == BluetoothGatt.STATE_CONNECTED) {
                    Log.d(TAG, "onConnectionStateChange: 连接成功");
                    mGattMap.put(address, gatt);
                    gatt.discoverServices();

                        /*mHandler.postDelayed(() -> write(address, "0000a950-0000-1000-8000-00805f9b34fb", "0000a951-0000-1000-8000-00805f9b34fb",
                                new byte[]{84, 13, 0, 3, 0, 0, 100}),2000);*/
                } else if (newState == BluetoothGatt.STATE_DISCONNECTED) {
                    Log.d(TAG, "onConnectionStateChange: 连接断开");
                    mGattMap.remove(address);
                    gatt.close();
                    mConnectEventUtil.onDisConnect(address, gatt);
                }
            }

            @Override
            public void onServicesDiscovered(BluetoothGatt gatt, int status) {
                super.onServicesDiscovered(gatt, status);
                if (status == BluetoothGatt.GATT_SUCCESS) {
                    Log.d(TAG, "onServicesDiscovered: 发现服务");
                    BluetoothGattService service;
                    //OTA相关的服务
                    try {
                        service = gatt.getService(BluetoothConstant.UUID_SERVICE);
                        Log.d(TAG, "onConnectionStateChange: 服务是否为空" + (service == null));
                        if (service != null) {
                            BluetoothGattCharacteristic characteristic = service.getCharacteristic(BluetoothConstant.UUID_NOTIFICATION);
                            if (characteristic != null) {
                                mReadCharacteristicList.add(characteristic);
                            }
                        }
                    } catch (Exception e) {

                    }

                    //数据通讯服务
                    try {
                        service = gatt.getService(UUID.fromString(uuid_server));
                        Log.d(TAG, "onConnectionStateChange: 服务是否为空" + (service == null));
                        if (service != null) {
                            BluetoothGattCharacteristic characteristic = service.getCharacteristic(UUID.fromString(uuid_notify));
                            if (characteristic != null) {
                                mReadCharacteristicList.add(characteristic);
                            }
                        }
                    } catch (Exception e) {

                    }

                    if (!startReadCharacteristic(gatt)) {
                        //协商mtu
                        gatt.requestMtu(512);
                    }
                }
            }

            @Override
            public void onDescriptorWrite(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) {
                super.onDescriptorWrite(gatt, descriptor, status);
                Log.d(TAG, "onDescriptorWrite: " + descriptor.getUuid());
                if (!startReadCharacteristic(gatt)) {
                    Log.d(TAG, "onDescriptorWrite: 开启完成");
                    //协商mtu
                    gatt.requestMtu(512);
                }
            }

            @Override
            public void onMtuChanged(BluetoothGatt gatt, int mtu, int status) {
                super.onMtuChanged(gatt, mtu, status);
                Log.d(TAG, "onMtuChanged : " + mtu);
                mConnectEventUtil.onMtuChanged(address, gatt, mtu, status);
                mConnectEventUtil.onConnectSuccess(address, gatt);
            }

            @Override
            public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
                super.onCharacteristicWrite(gatt, characteristic, status);
                for (CharacteristicCallbackInterface characteristicCallbackInterface : mCharacteristicCallbackList) {
                    characteristicCallbackInterface.onCharacteristicWrite(gatt, characteristic, status);
                }
            }

            @Override
            public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
                super.onCharacteristicChanged(gatt, characteristic);
                byte[] value = characteristic.getValue();
                Log.d(TAG, "读取到数据: " + characteristic.getUuid() + "   " + Arrays.toString(value));
                for (CharacteristicCallbackInterface characteristicCallbackInterface : mCharacteristicCallbackList) {
                    characteristicCallbackInterface.onCharacteristicChanged(gatt, characteristic, value);
                }
            }
        });
    }

    public void disconnect(String address) {
        disconnect(address, mGattMap.get(address));
    }

    public void disconnect(String address, BluetoothGatt gatt) {
        if (gatt != null) {
            gatt.disconnect();
            gatt.close();
            mGattMap.remove(address);
            mConnectEventUtil.onDisConnect(address, gatt);
        }
    }

    public BluetoothGatt getLatestConnectedBtGatt() {
        if (mGattMap.isEmpty()) {
            return null;
        } else {
            BluetoothGatt g = null;
            for (BluetoothGatt gatt : mGattMap.values()) {
                g = gatt;
            }
            return g;
        }
    }

    public boolean write(String address, String serviceUUID, String characteristicUUID, byte[] data) {
        return write(address, UUID.fromString(serviceUUID), UUID.fromString(characteristicUUID), data);
    }

    public boolean write(String address, UUID serviceUUID, UUID characteristicUUID, byte[] data) {
        BluetoothGatt gatt = mGattMap.get(address);
        return write(gatt, serviceUUID, characteristicUUID, data);
    }

    @SuppressLint("MissingPermission")
    public boolean write(BluetoothGatt gatt, UUID serviceUUID, UUID characteristicUUID, byte[] data) {
        return WriteUtil.write(gatt, serviceUUID, characteristicUUID, data);
    }

    /**
     * 停止扫描
     */
    public void stopScan() {
        mHandler.removeCallbacks(mScanTimeOut);
        if (mBluetoothLeScanner != null) {
            mBluetoothLeScanner.stopScan(mScanCallback);
        }
        for (ScanCallbackInterface scanCallbackInterface : mScanCallbackList) {
            scanCallbackInterface.onStopScan();
        }
    }

    public boolean isBluetoothEnable() {
        return mBluetoothAdapter != null && mBluetoothAdapter.isEnabled();
    }

    public void setUUIDInfo(Map<String, String> map) {
        //打印
        for (Map.Entry<String, String> entry : map.entrySet()) {
            Log.d(TAG, "setUUIDInfo: " + entry.getKey() + "   " + entry.getValue());
        }
        uuid_server = map.get("uuid_server");
        uuid_write_1 = map.get("uuid_write_1");
        uuid_write_2 = map.get("uuid_write_2");
        uuid_notify = map.get("uuid_notify");

        uuid_server_ota = map.get("uuid_server_ota");
        uuid_write_ota = map.get("uuid_write_ota");
        uuid_notify_ota = map.get("uuid_notify_ota");

    }
}
